/*
 * UndoManager.java
 * 撤消管理器
 * Created on 2007年10月15日, 下午10:03
 */

package cn.tearcry.jsudoku;
import java.awt.Component;
import java.util.*;

/**
 * 撤消管理器，提供撤消以及恢复撤消功能，可以动态刷新控制组件的使能状态
 * @author 马建乐
 */
public class UndoManager {
    /** 撤消栈 */
    private MyStack undoStack;
    /** 恢复撤消栈 */
    private MyStack redoStack;
    /** 撤消控制组件数组 */
    private Component[] undoComponents;
    /** 恢复撤消控制组件数组 */
    private Component[] redoComponents;
    /** GridButtonFactory 代理 */
    private GridButtonFactory factory;
    /** 数独按钮 */
    private GridButton[][] gridArray;
    
    /**
     * 创建一个新的撤消管理器
     * @param gbf 提供相关游戏的GridButtonFactory代理对象
     * @param uc 控制撤消功能的组件数组，刷新状态用
     * @param rc 控制恢复撤消功能的组件数组，刷新状态用
     */
    public UndoManager(GridButtonFactory gbf,Component[] uc,Component[] rc) {
        undoStack=new MyStack();
        redoStack=new MyStack();
        factory=gbf;
        gridArray=gbf.getGridArray();
        undoComponents=uc;
        redoComponents=rc;
    }
    
    /**
     * 记录操作信息
     * @param int[] 操作信息:
     * int[0] 列  int[1]行 int[2]数字
     */
    public void record(int[] info) {
       if(info.length>3)
           return;
        undoStack.put(info);  
        updateRedoState();
        updateUndoState();
    }
    /*
     * 撤消
     */
    public void undo() {
        if(canUndo()) {
            //info 0:row 1:column 2:num
           int[] info=(int[])undoStack.pop();
           redoStack.put(info);
           gridArray[info[0]][info[1]].removeNum();
           factory.backOnStep();
           if(factory.getDisplayCandidates())
               factory.displayCandidates();
        } 
        
        updateRedoState();
        updateUndoState();
        return;
    }
    
    /**
     * 恢复撤消
     */
     public void redo() {
        if(canRedo()) {
            int[] info=(int[])redoStack.pop();
            undoStack.put(info);
            gridArray[info[0]][info[1]].setNum(info[2]);
        } 
        factory.goOneStep();
        updateRedoState();
        updateUndoState();
        return;
    }
    /**
     * 返回是否可以撤消
     * @return boolean 是否可以撤消
     */
    public boolean canUndo(){
        if(undoStack.isEmpty())
            return false;
        else
            return true;
    }
    /**
     * 返回是否可以恢复撤消
     * @return boolean 是否可以恢复撤消
     */
     public boolean canRedo(){
        if(redoStack.isEmpty())
            return false;
        else
            return true;
    }
     
    /**
     *刷新撤消控制组件的使能状态
     */
    public void updateUndoState() {
        if(undoStack.isEmpty()) {
        for(int i=0;i<undoComponents.length;i++) 
            undoComponents[i].setEnabled(false);
        }
        else {
            for(int i=0;i<undoComponents.length;i++) 
            undoComponents[i].setEnabled(true);
        }
    }
    
    /**
     *刷新恢复撤消控制组件的使能状态
     */
     public void updateRedoState() {
        if(redoStack.isEmpty()) {
        for(int i=0;i<redoComponents.length;i++) 
            redoComponents[i].setEnabled(false);
        }
        else {
            for(int i=0;i<redoComponents.length;i++) 
            redoComponents[i].setEnabled(true);
        }
     }
     
     public void restoreManager() {
         undoStack.clearAll();
         redoStack.clearAll();
         updateUndoState();
         updateRedoState();
     }
    
    /**
     * 定义栈及相关方法
     */
    static class MyStack {
        private LinkedList data=new LinkedList();
        
        /**
         *入栈
         */
        public void put(Object obj) {
            data.addFirst(obj);
        }
        
        /**
         *出栈
         */
        public Object pop() {
             if(isEmpty())
                return null;
            else
                return data.removeFirst();
        }
        
        /*
         * 判断栈是否为空
         * @return boolean 栈是否为空
         */
        public boolean isEmpty() {
            return data.isEmpty();
        }
        
        public void clearAll() {
            for(int i=0;i<data.size();i++)
                data.remove(0);
        }
    }
}